/*
    多进程统计 Linux 内核中 .c、.h 文件的文件数及文件的总行和
    每个文件，启动一个新进程，总行数
*/

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

typedef struct wc_count
{
    int file;
    int folder;
    int link;
    int file_c;
    int file_h;
    int row_c;
    int row_h;
}wc_count;

typedef struct ret
{
    int flag;
    int row;
}ret;

void wc_cInit(wc_count* wc_c);
void dp_count(char* address, wc_count* wc_c);
void wc_c_safe(wc_count* wc_c);
void* routine(void* avg);
int is_source_file(const char *filename);

int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        perror("参数传输错误！\n");
        exit(1);
    }
    wc_count wc_c;
    wc_cInit(&wc_c);
    dp_count(argv[1], &wc_c);

    printf("%s中%d个文件夹，%d个文件, %d个链接\n",argv[1], wc_c.folder, wc_c.file, wc_c.link);
    printf("包含%d 个 .c 文件 一共 %d 行，%d 个 .h 文件 一共 %d 行\n", wc_c.file_c, wc_c.row_c, wc_c.file_h, wc_c.row_h);
    return 0;
}

void wc_cInit(wc_count* wc_c)
{
    wc_c->file = 0;
    wc_c->file_c = 0;
    wc_c->file_h = 0;
    wc_c->folder = 0;
    wc_c->link = 0;
    wc_c->row_c = 0;
    wc_c->row_h = 0;
}

void dp_count(char* address, wc_count* wc_c)
{
    //打开目录流
    DIR *dir;
    dir = opendir(address);
    if(!dir)
    {
        perror("打开目录失败！\n");
        exit(1);
    }
    struct dirent* read_dir;
    char name[1024];
    while(read_dir = readdir(dir))
    {
        // 文件名为 . 或者 .. 的跳过
        if(!strcmp(read_dir->d_name, ".") || !strcmp(read_dir->d_name, ".."))
            continue;
        snprintf(name, sizeof(name), "%s/%s", address, read_dir->d_name);
        if(read_dir->d_type == 4)
        {
            wc_c->folder++;
            dp_count(name, wc_c); 
        }
        if(read_dir->d_type == 8)
        {
            wc_c->file++;
            if(!strcmp(read_dir->d_name + strlen(read_dir->d_name) - 2, ".c") || !strcmp(read_dir->d_name + strlen(read_dir->d_name) - 2, ".h"))
            {
                if(!strcmp(read_dir->d_name + strlen(read_dir->d_name) - 2, ".c"))
                    wc_c->file_c++;
                else
                    wc_c->file_h++;
                //分配一块足够大的内存空间，将指定字符串的内容复制进去，并返回指向这块内存的指针。
                char* fullpath = strdup(name); // 分配独立内存传给线程
                //todo 创建线程来读取文件.c .h 文件的行数
                if(ret)
                {
                    printf("线程创建失败!\n");
                    exit(1);
                }
                wc_c_safe(wc_c);
            }
        }
        if(read_dir->d_type == 10)
            wc_c->link++;
    }
    closedir(dir);
}

void* routine(void* avg)
{
    ret* ret1 = (ret*)malloc(sizeof(ret));
    ret1->row = 0; // 必须初始化
    char* filename = (char*) avg;
    FILE* fp = fopen(filename, "r");
    if (!fp) {
        perror("fopen");
        free(filename); // 释放 strdup 的内存
        pthread_exit(NULL);
    }
    int ch;
    while ((ch = fgetc(fp)) != EOF) {
        if (ch == '\n')
            ret1->row++;
    }
    fclose(fp);
    printf("%s 文件中有%d行数据\n", filename, ret1->row);
    ret1->flag = is_source_file(filename);
    free(filename); // 释放 strdup 的内存
    return ret1; 
}

// 判断是否是 .c 或 .h 文件
int is_source_file(const char *filename) {
    int len = strlen(filename);
    if (len >= 2 && filename[len - 2] == '.' && filename[len - 1] == 'c') return 1; // .c
    if (len >= 2 && filename[len - 2] == '.' && filename[len - 1] == 'h') return 2; // .h
    return 0;
}